前言:
在尋找轉換模組的方法時,也順便寫了MacOS版本的訓練模組
MacOS程式碼:
import os
import tensorflow as tf
import coremltools
import keras
from tensorflow import keras
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.models import Model, Sequential, load_model
from tensorflow.python.keras.layers import LSTM, Flatten, Dense, Dropout
from tensorflow.python.keras.applications.resnet50 import ResNet50
from tensorflow.python.keras.optimizer_v2.adam import Adam
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
from tensorflow.python.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
import ssl
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
ssl._create_default_https_context = ssl._create_unverified_context
def create_model():
# 捨棄 ResNet50 頂層的 fully connected layers
net = ResNet50(include_top=False,
weights='imagenet',
input_tensor=None,
input_shape=(IMAGE_SIZE[0],IMAGE_SIZE[1],3))
x = net.output
x = Flatten()(x)
# 增加 DropOut layer
x = Dropout(0.5)(x)
# 增加 Dense layer,以 softmax 產生個類別的機率值
output_layer = Dense(NUM_CLASSES, activation='softmax', name='softmax')(x)
# 設定凍結與要進行訓練的網路層
net_final = Model(inputs=net.input, outputs=output_layer)
for layer in net_final.layers[:FREEZE_LAYERS]:
layer.trainable = False
for layer in net_final.layers[FREEZE_LAYERS:]:
layer.trainable = True
# 使用 Adam optimizer,以較低的 learning rate 進行 fine-tuning
net_final.compile(optimizer=Adam(learning_rate=1e-5),
loss='categorical_crossentropy', metrics=['accuracy'])
return net_final
# 資料路徑
DATASET_PATH = '/Users/pecajo/Desktop/pyFile/Demo1/'
# 影像大小
IMAGE_SIZE = (300, 300)
# 影像類別數
NUM_CLASSES = 133
# 若 GPU 記憶體不足,可調降 batch size 或凍結更多層網路
BATCH_SIZE = 8
# 凍結網路層數
FREEZE_LAYERS = 0
# Epoch 數
NUM_EPOCHS = 1
# 模型輸出儲存的檔案
WEIGHTS_FINAL = '/Users/使用者名稱/Desktop/pyFile/Demo1/model-resnet50-macOS-1.h5'
# 透過 data augmentation 產生訓練與驗證用的影像資料
train_datagen = ImageDataGenerator(rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
channel_shift_range=10,
horizontal_flip=True,
vertical_flip = True,
fill_mode='nearest',
data_format='channels_last'
)
train_batches = train_datagen.flow_from_directory(DATASET_PATH + 'dogImages/train',
target_size=IMAGE_SIZE,
interpolation='bicubic',
class_mode='categorical',
shuffle=True,
batch_size=BATCH_SIZE)
valid_datagen = ImageDataGenerator()
valid_batches = valid_datagen.flow_from_directory(DATASET_PATH + 'dogImages/valid',
target_size=IMAGE_SIZE,
interpolation='bicubic',
class_mode='categorical',
shuffle=False,
batch_size=BATCH_SIZE)
# 輸出各類別的索引值
for cls, idx in train_batches.class_indices.items():
print('Class #{} = {}'.format(idx, cls))
# Create a basic model instance
net_final = create_model()
# 輸出整個網路結構
print(net_final.summary())
if os.path.exists(DATASET_PATH):
if os.path.exists(DATASET_PATH + WEIGHTS_FINAL):
print(WEIGHTS_FINAL + "模型存在,將繼續訓練模型")
# net_final.save(WEIGHTS_FINAL)
new_net_final = load_model(WEIGHTS_FINAL)
while True :
new_net_final.fit(train_batches,
steps_per_epoch = train_batches.samples // BATCH_SIZE,
validation_data = valid_batches,
validation_steps = valid_batches.samples // BATCH_SIZE,
epochs = NUM_EPOCHS)#,
# callbacks = [LR_function])
# 儲存訓練好的模型
print("儲存訓練模型")
new_net_final.save(WEIGHTS_FINAL) # .h5
else:
print(WEIGHTS_FINAL + '模型不存在,將新建訓練模型')
# 訓練模型
while True :
net_final.fit(train_batches,
# validation_split = 0.2,
steps_per_epoch = train_batches.samples // BATCH_SIZE,
validation_data = valid_batches,
validation_steps = valid_batches.samples // BATCH_SIZE,
epochs = NUM_EPOCHS)#,
# callbacks = [LR_function])
# 儲存訓練好的模型
print("儲存訓練模型")
net_final.save(WEIGHTS_FINAL) # .h5
else:
print(WEIGHTS_FINAL + '路徑不存在,請確認路徑')